Skip to content

Conversation

@geekbeast
Copy link

This change allows retrieving values from the map without having to acquire a write lock, unless the value is missing. For read once (or mostly read) workloads this is superior to taking a write lock everytime the entry is read. It also saves having to allocate value if it is not inserted and having to compute the usize hash / shard index twice versus the approach of calling get then using entry to insert (as there is not try_insert yet)

Unfortunately, it doesn't seem like it is possible to avoid the second read without changing the behavior of HashMap.

This change allows retrieving values from the map without having to acquire a write lock, unless the value is missing. For read once (or mostly read) workloads this is superior to taking a write lock
everytime the entry is read. It also saves having to allocate value if it is not inserted and having to compute the usize hash / shard index twice versus the approach of calling get then using entry to insert (as there is not try_insert yet)

Unfortunately, it doesn't seem like it is possible to avoid the second read without changing the behavior of HashMap.
@geekbeast
Copy link
Author

I didn't touch dependencies so not sure why home package all of sudden is requiring a newer rustc.

let c: K = ptr::read(&key);
let mut shard = self._yield_write_shard(idx);

shard.insert(key, SharedValue::new(value(&c)));
Copy link

@ryoqun ryoqun Apr 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think there could be a race here? when multiple threads are racing with get_or_insert() for the same missing key, all threads could reach here, resulting replacing writes from other threads? That's because it's not atomic to drop the read shard above and yield write shard here?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, you're right.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't any better than calling .get() and insert if it isn't there. So this doesn't add anything.

@ryoqun
Copy link

ryoqun commented May 8, 2024

@xacrimon I wonder this pr could ever be merged soonish? if more efforts are needed, i can work on. cc: @geekbeast

@ryoqun
Copy link

ryoqun commented Jun 20, 2024

@xacrimon I wonder this pr could ever be merged soonish? if more efforts are needed, i can work on. cc: @geekbeast

@xacrimon (thanks for recent release with perf increase!) friendly reminder. if this api sounds okay, I'm available to work on this pr. cc: @geekbeast

@ryoqun
Copy link

ryoqun commented Aug 2, 2024

@xacrimon a friendly ping. :)

@ryoqun
Copy link

ryoqun commented Aug 30, 2024

@xacrimon a friendly ping. sorry for being persistent here. my work is kind of blocked on this. can i jump ahead and recreate a pr?

let c: K = ptr::read(&key);
let mut shard = self._yield_write_shard(idx);

shard.insert(key, SharedValue::new(value(&c)));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't any better than calling .get() and insert if it isn't there. So this doesn't add anything.

drop(shard);

unsafe {
let c: K = ptr::read(&key);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, K is duplicated illegally, can't do this. Violated standard rust rules and this also means K is dropped twice. If you use allocating string keys this segfaults.

Ref::new(shard, kptr, vptr)
}
} else {
drop(shard);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, someone else can insert key, which causes us to loose updates.

@xacrimon
Copy link
Owner

xacrimon commented Feb 1, 2025

@xacrimon a friendly ping. sorry for being persistent here. my work is kind of blocked on this. can i jump ahead and recreate a pr?

hihi, sorry ive been away and very busy. yes, i'd take prs to implement this API if they're implemented in an atomic way that makes it better to use than get + insert in sequence. thank you <3

@xacrimon
Copy link
Owner

xacrimon commented Feb 1, 2025

This change allows retrieving values from the map without having to acquire a write lock, unless the value is missing. For read once (or mostly read) workloads this is superior to taking a write lock everytime the entry is read. It also saves having to allocate value if it is not inserted and having to compute the usize hash / shard index twice versus the approach of calling get then using entry to insert (as there is not try_insert yet)

Unfortunately, it doesn't seem like it is possible to avoid the second read without changing the behavior of HashMap.

if you mean the illegal and very bug-causing ptr::read call that's not really an option to just ignore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants